package pdm.traj.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import pdm.traj.conf.TrajConf;
import pdm.traj.entity.PartInfo;
import pdm.traj.entity.TrackPoint2;
import pdm.traj.entity.TrajQuery;
import pdm.traj.entity.TrajQueryResult;
import pdm.traj.query.impl.QueryMultiTraj;
import pdm.traj.query.impl.QueryTask;
import pdm.traj.service.KeyService;
import pdm.traj.service.PartService;
import pdm.traj.service.TrajDataService;
import pdm.traj.update.UpdateTraj;
import pdm.traj.util.StringUtil;
import pdm.traj.util.TrackPointUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisConnectionException;

public class TrajDataServiceImpl implements TrajDataService {
//	public static final int UPDATE_BUSY_BITMAP_SIZE = 100;
//	public static final double 
//	private int updateBusyBitmapSize = TrajConf.getInstance().getIntProperty(TrajConf.UPDATE_BUSY_BITMAP_SIZE);
//	private int updateBusyBitmapSizeHalf = updateBusyBitmapSize / 2;
//	private double updateBusyBitmapSizeDouble = (double) updateBusyBitmapSize;
//	private double updateBusyBitmapSizeHalfDouble = (double) updateBusyBitmapSizeHalf;
//	private double updateCalcThreshold = TrajConf.getInstance().getDoubleProperty(TrajConf.UPDATE_CALC_THRESHOLD);
//	private long updateBusyCheckCycle = TrajConf.getInstance().getLongProperty(TrajConf.UPDATE_BUSY_CHECK_CYCLE);
	
	public static final String TAG = "TrajDataServiceImpl";
	private final Log log = LogFactory.getLog(getClass());
	private static final Integer m1 = new Integer(-1);
	PartService partService;
	KeyService keyService;
	
//	Map<Integer, UpdateTraj> updateTrajs;

//	private List<Boolean> updateBusyBitmap;
//	private Date startImport;
//	private Date endImport;
	
	public void init() {
//		System.out.println(TAG + " init()");
//		updateBusyBitmap = new LinkedList<Boolean>();		
//		updateTrajs = new Hashtable<Integer, UpdateTraj>();
//		List<PartInfo> piList = partService.getAllPartInfo();
//		for (PartInfo pi : piList) {
////			System.out.println("partInfo: " + StringUtil.beanToJson(pi));
//			Integer index = partService.getPIIndexByPartInfo(pi);
//			if (!index.equals(m1)) {
//				try {
//					UpdateTraj updateTraj = new UpdateTraj(pi.getIp(), Integer.parseInt(pi.getPort()));
//					updateTraj.setKeyService(keyService);
//					updateTrajs.put(index, updateTraj);
////					updateTraj.init();
////					Thread.sleep(200);
//					Thread t = new Thread(updateTraj);
//					t.start();					
//				} catch (NumberFormatException nfe) {
//					nfe.printStackTrace();
//				}
//			}
//		}
//		System.out.println(TAG + ": updateTrajs size is " + updateTrajs.size());
//		for (int i = 0; i < updateBusyBitmapSize; i++) {
//			updateBusyBitmap.add(false);
//		}
//		TimerTask cus = new CheckUpdateState();
//		Timer t = new Timer();
//		t.scheduleAtFixedRate(cus, updateBusyCheckCycle, updateBusyCheckCycle);
//		TimerTask cus2 = new CheckUpdateState2();
//		Timer t2 = new Timer();
//		t2.scheduleAtFixedRate(cus2, 20000, 20000);
//		t2.scheduleAtFixedRate(cus2, 5000, 5000);
	}
//	
//	class CheckUpdateState2 extends TimerTask {
//
//		@Override
//		public void run() {
//			int c1 = 0, c2 = 0, i;
//			for (i = 0; i < updateBusyBitmapSize; i++) {
//				if (updateBusyBitmap.get(i)) {
//					c1++;
//				} else {
//					c2++;
//				}
//			}
//			if (c1 == updateBusyBitmapSize) {
//				log.info("update busy");
//			} 
//			if (c2 == updateBusyBitmapSize) {
//				log.info("update idle");
//			}
//		}
//		
//	}
//	class CheckUpdateState extends TimerTask {
//		
//		@Override
//		public void run() {
//			boolean updateBusy = false;
//			for (Integer updateTrajIndex : updateTrajs.keySet()) {
//				UpdateTraj updateTraj = updateTrajs.get(updateTrajIndex);
//				if (updateTraj.getCurListSize() > 0) {
//					updateBusy = true;
//					break;
//				}
//			}
//			updateBusyBitmap.add(updateBusy);
//				updateBusyBitmap.remove(0);
//			scanUpdateBusyBitmap();
//		}
//		
//		private void scanUpdateBusyBitmap() {
//			int c1 = 0, c2 = 0, i;
//			double d1, d2;
//			for (i = 0; i < updateBusyBitmapSizeHalf; i++) {
//				if (updateBusyBitmap.get(i)) {
//					c1++;
//				}
//			}
//			for (; i < updateBusyBitmapSize; i++) {
//				if (updateBusyBitmap.get(i)) {
//					c2++;
//				}
//			}
//			d1 = (double) c1 / updateBusyBitmapSizeHalfDouble;
//			d2 = (double) c2 / updateBusyBitmapSizeHalfDouble;
//			if (d1 >= updateCalcThreshold && (1.0 - d2) >= updateCalcThreshold) {
//				log.info("Traj import finish");
//				endImport = new Date();
//				for (i = 0; i < updateBusyBitmapSize; i++) {
//					updateBusyBitmap.set(i, false);
//				}
//				if (startImport != null) {
//					long diff = endImport.getTime() - startImport.getTime();
//					log.info(diff + " ms used");
//					log.info(diff / 1000 + " s used");
//					log.info(diff / 1000.0 / 60 + " minutes used");
//				}
//			} else if ((1.0 - d1) > updateCalcThreshold && d2 >= updateCalcThreshold) {
//				log.info("Traj import start");
//				startImport = new Date();
//				for (i = 0; i < updateBusyBitmapSize; i++) {
//					updateBusyBitmap.set(i, true);
//				}
//			} 
//		}
//	}
//
//	@Override
//	public int update(TrackPoint2 tp) {
//		Integer index = partService.getPIIndexByTP(tp);
//		if (!index.equals(m1)) {
//			updateTrajs.get(index).update(tp);
//		}
//		return 1;
//	}

	@Override
	public List<TrackPoint2> queryMultiTrajTPList(TrajQuery query) {
		List<TrackPoint2> result = null;
		QueryTask qt = new QueryTask();
		qt.setQuery(query);
		qt.setKeyService(keyService);
		qt.setPartService(partService);
//		System.out.println(TAG + " queryMultiTrajTPList: query start");
		log.info("partplan: " + partService.getKeyPrefix());
		log.info("query: " + StringUtil.beanToJson(query));
		Date sd = new Date();
		log.info("query execute start");
		qt.start();
		try {
			qt.join();
			Date ed = new Date();
			log.info("query execute end");
			log.info((ed.getTime() - sd.getTime()) + " ms used"); 
			result = qt.getResult();
//			System.out.println(TAG + "queryMultiTrajTPList: query end");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return result;
	}
	
//	@Override
//	public List<TrackPoint2> queryMultiTrajTPList(TrajQuery query) {
//		//check query input
//		List<TrackPoint2> result = new ArrayList<TrackPoint2>();
//		List<PartInfo> partInfo = partService.getPartInfoByQuery(query);
//		for (PartInfo pi : partInfo) {
//			List<String> k = keyService.getKeysByPartInfoAndQuery(pi, query);
//			QueryMultiTraj cli = new QueryMultiTraj();
//			cli.setIp(pi.getIp());
//			cli.setPort(pi.getPort());
//			cli.setKeys(k);
//			cli.setUids(query.getUids());
//			cli.start();
//			try {
//				cli.join();
//				result.addAll(cli.getResult());
//			} catch (InterruptedException e) {
//				e.printStackTrace();
//			}
//		}
//		return result;
//	}
	
//	@Override
//	public List<TrackPoint2> queryTPListByDuration(String startTime, String endTime) {
//		TrajQuery query = new TrajQuery();
//		query.setStartTime(startTime);
//		query.setEndTime(endTime);
//		TrajQueryResult result = this.query(query);
//		return result.getResult();
//	}
	
//	@Override
//	public List<TrackPoint2> queryTPList(TrajQuery query) {
//		List<TrackPoint2> result = new ArrayList<TrackPoint2>();
//		return result;
//	}
//	@Override
//	public int deleteAll() {
//		System.out.println("TrajDataServiceImpl: query");
//		return 0;
//	}
	
	public PartService getPartService() {
		return partService;
	}
	public void setPartService(PartService partService) {
		this.partService = partService;
	}

	public KeyService getKeyService() {
		return keyService;
	}

	public void setKeyService(KeyService keyService) {
		this.keyService = keyService;
	}

//	@Override
//	public TrajQueryResult query(TrajQuery query) {
//		return null;
//	}

}
